(include "lib/asm/class.inc")

(def-class obj :nil
	(dec-method :vtable class/obj/vtable)
	(dec-method :deinit class/obj/null :virtual (:r0) (:r0))
	(dec-method :type class/obj/type :virtual (:r0) (:r0 :r1))
	(dec-method :hash class/obj/hash :virtual (:r0) (:r0 :r1))
	(dec-method :eql class/obj/eql :virtual (:r0 :r1) (:r0 :r1))
	(dec-method :print class/obj/print :virtual (:r0 :r1) (:r0))
	(dec-method :null class/obj/null)
	(dec-method :destroy class/obj/destroy :static (:r0))
	(dec-method :init class/obj/init :static (:r0 :r1) (:r0 :r1))
	(dec-method :inst_of class/obj/inst_of :static (:r0 :r1) (:r0 :r1))
	(dec-method :ref class/obj/ref :static (:r0) (:r0))
	(dec-method :deref class/obj/deref :static (:r0))
	(dec-method :ref_if class/obj/ref_if :static (:r0) (:r0))
	(dec-method :deref_if class/obj/deref_if :static (:r0))
	(dec-method :lisp_eql class/obj/lisp_eql :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_nql class/obj/lisp_nql :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_get class/obj/lisp_fget :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_set class/obj/lisp_fset :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_hash class/obj/lisp_hash :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_weak_ref class/obj/lisp_wref :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_obj_ref class/obj/lisp_oref :static (:r0 :r1) (:r0 :r1))
	(dec-method :lisp_type class/obj/lisp_type :static (:r0 :r1) (:r0 :r1)))

(def-struct obj 0
	(pptr vtable)
	(uint count))

;;;;;;;;;;;;;;;;
; inline methods
;;;;;;;;;;;;;;;;

(defun class/obj/init ()
	;inputs
	;:r0 = object (ptr)
	;:r1 = vtable (pptr)
	;outputs
	;:r0 = object (ptr)
	;:r1 = 0 if error, else ok
	;trashes
	;:r1
	(assign '(:r1 1) '((:r0 obj_vtable) :r1))
	(assign '(:r1) '((:r0 obj_count))))

(defun class/obj/ref (&optional o c x)
	;inputs
	;:r0 = object (ptr)
	;outputs
	;:r0 = object (ptr)
	;trashes
	;:r1
	(setd o :r0 c :r1 x 1)
	(if (eql o c) (throw "Invalid object or count !" (list o c)))
	(assign `((,o obj_count)) `(,c))
	(if (vp-reg? x)
		(vp-add-rr x c)
		(vp-add-cr x c))
	(assign `(,c) `((,o obj_count))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; field helpers, sorted load, saves and transfer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun load-fields (base fields tmps)
	(defq src (list) dst (list))
	(each (# (push src (list base (first %0))) (push dst (second %0)))
		(sort (partition (zip fields tmps (map (const eval) fields)) 3)
			(# (- (last %0) (last %1)))))
	(assign src dst))

(defun save-fields (base fields tmps)
	(defq src (list) dst (list))
	(each (# (push src (second %0)) (push dst (list base (first %0))))
		(sort (partition (zip fields tmps (map (const eval) fields)) 3)
			(# (- (last %0) (last %1)))))
	(assign src dst))

(defun assign-fields (src src_fields dst dst_fields tmps)
	(load-fields src src_fields tmps)
	(save-fields dst dst_fields tmps))
